/*
 * FreeModbus Libary: user callback functions and buffer define in slave mode
 * Copyright (C) 2013 Armink <armink.ztl@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * File: $Id: user_mb_app.c,v 1.60 2013/11/23 11:49:05 Armink $
 */
#include "user_freemodbus_lite_demo.h"

/*------------------------Slave mode use these variables----------------------*/
//从机模式：离散输入变量
#if S_DISCRETE_INPUT_NDISCRETES_Number%8
uint8_t WHT_SDiscIn_Buffer[S_DISCRETE_INPUT_NDISCRETES_Number/8+1];
#else
uint8_t WHT_SDiscIn_Buffer[S_DISCRETE_INPUT_NDISCRETES_Number/8]  ;
#endif

//从机模式：线圈变量
#if S_COIL_NCOILS_Number%8
uint8_t WHT_SCoil_Buffer[S_COIL_NCOILS_Number/8+1];
#else
uint8_t WHT_SCoil_Buffer[S_COIL_NCOILS_Number/8];
#endif

//从机模式：输入寄存器变量
uint16_t WHT_SRegIn_Buffer[S_REG_INPUT_NREGS_Count];

//从机模式：保持寄存器变量
uint16_t WHT_SRegHold_Buffer[S_REG_HOLDING_NREGS_Count];

/**
 * Modbus从机输入寄存器回调函数
 *
 * @param pucRegBuffer 输入寄存器缓冲区
 * @param usAddress 输入寄存器地址
 * @param usNRegs 输入寄存器序号
 *
 * @return result
 */
eMBErrorCode WHT_MB_RegInput_Callback(unsigned char* pucRegBuffer, unsigned short usAddress, unsigned short usNRegs)
{
    eMBErrorCode eStatus = MB_ENOERR;
    unsigned short iRegIndex;

    /* 它已经在modbus功能方法中加1了 */
    usAddress--;
    if ((usAddress >= S_REG_Input_Start_Pos) && (usAddress + usNRegs <= S_REG_Input_Start_Pos + S_REG_INPUT_NREGS_Count))
    {
        iRegIndex = usAddress - S_REG_Input_Start_Pos;
        while (usNRegs > 0)
        {
            *pucRegBuffer++ = (unsigned char) (WHT_SRegIn_Buffer[iRegIndex] >> 8);
            *pucRegBuffer++ = (unsigned char) (WHT_SRegIn_Buffer[iRegIndex] & 0xFF);
            iRegIndex++;
            usNRegs--;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

/**
 * Modbus从机保持寄存器回调函数
 *
 * @param pucRegBuffer 保持寄存器缓冲区
 * @param usAddress 保持寄存器地址
 * @param usNRegs 保持寄存器编号
 * @param eMode 读或写
 *
 * @return result
 */
eMBErrorCode WHT_MB_RegHolding_Callback(unsigned char* pucRegBuffer, unsigned short usAddress, unsigned short usNRegs, eMBRegisterMode eMode)
{
    eMBErrorCode eStatus = MB_ENOERR;
    unsigned short iRegIndex;

    /* 它在modbus功能方法中已经加了1 */
    usAddress--;
    if ((usAddress >= S_REG_HOLDING_START_Pos) && (usAddress + usNRegs <= S_REG_HOLDING_START_Pos + S_REG_HOLDING_NREGS_Count))
    {
        iRegIndex = usAddress - S_REG_HOLDING_START_Pos;
        switch (eMode)
        {
        /* 从协议栈读取当前寄存器的值 */
        case MB_REG_READ:
            while (usNRegs > 0)
            {
                *pucRegBuffer++ = (unsigned char) (WHT_SRegHold_Buffer[iRegIndex] >> 8);
                *pucRegBuffer++ = (unsigned char) (WHT_SRegHold_Buffer[iRegIndex] & 0xFF);
                iRegIndex++;
                usNRegs--;
            }
            break;
        /* 用来自协议栈的新值写入当前寄存器值 */
        case MB_REG_WRITE:
            while (usNRegs > 0)
            {
                WHT_SRegHold_Buffer[iRegIndex] = *pucRegBuffer++ << 8;
                WHT_SRegHold_Buffer[iRegIndex] |= *pucRegBuffer++;
                iRegIndex++;
                usNRegs--;
            }
            break;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

/**
 * Modbus 从属线圈回调函数
 *
 * @param pucRegBuffer 线圈缓冲器
 * @param usAddress 线圈地址
 * @param usNCoils 线圈数量
 * @param eMode 读取或写入
 *
 * @return result
 */
eMBErrorCode WHT_MB_RegCoils_Callback(unsigned char* pucRegBuffer, unsigned short usAddress, unsigned short usNCoils, eMBRegisterMode eMode)
{
    eMBErrorCode eStatus = MB_ENOERR;
    unsigned short iRegIndex , iRegBitIndex , iNReg;

    iNReg =  usNCoils / 8 + 1;
    /* 它在Modbus功能方法中已经加1了 */
    usAddress--;
    if((usAddress >= S_COIL_START_Pos) && (usAddress + usNCoils <= S_COIL_START_Pos + S_COIL_NCOILS_Number))
    {
        iRegIndex = (unsigned short) (usAddress - S_COIL_START_Pos) / 8;
        iRegBitIndex = (unsigned short) (usAddress - S_COIL_START_Pos) % 8;
        switch ( eMode )
        {
        /* 从协议栈读取当前的线圈值 */
        case MB_REG_READ:
            while (iNReg > 0)
            {
                *pucRegBuffer++ = WHT_MB_Util_Get_Bits(&WHT_SCoil_Buffer[iRegIndex++], iRegBitIndex, 8);
                iNReg--;
            }
            pucRegBuffer--;
            /* 最后的线圈 */
            usNCoils = usNCoils % 8;
            /* 向高位补零 */
            *pucRegBuffer = *pucRegBuffer << (8 - usNCoils);
            *pucRegBuffer = *pucRegBuffer >> (8 - usNCoils);
            break;
            /* 用来自协议栈的新值写入当前线圈值 */
        case MB_REG_WRITE:
            while (iNReg > 1)
            {
                WHT_MB_Util_Set_Bits(&WHT_SCoil_Buffer[iRegIndex++], iRegBitIndex, 8, *pucRegBuffer++);
                iNReg--;
            }
            /* 最后的线圈 */
            usNCoils = usNCoils % 8;
            /* 当ucNBits为零时，WHT_MB_Util_Set_Bits存在程序缺陷 */
            if (usNCoils != 0)
            {
                WHT_MB_Util_Set_Bits(&WHT_SCoil_Buffer[iRegIndex++], iRegBitIndex, usNCoils, *pucRegBuffer++);
            }
            break;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

/**
 * Modbus从机离散量回调函数
 *
 * @param pucRegBuffer 离散缓冲区
 * @param usAddress 离散地址
 * @param usNDiscrete 离散数量
 *
 * @return result
 */
eMBErrorCode WHT_MB_RegDiscrete_Callback(unsigned char* pucRegBuffer, unsigned short usAddress, unsigned short usNDiscrete)
{
    eMBErrorCode eStatus = MB_ENOERR;
    unsigned short iRegIndex , iRegBitIndex , iNReg;

    iNReg =  usNDiscrete / 8 + 1;
    /* 它在modbus功能方法中已经加1了 */
    usAddress--;
    if ((usAddress >= S_DISCRETE_INPUT_START_Pos) && (usAddress + usNDiscrete <= S_DISCRETE_INPUT_START_Pos + S_DISCRETE_INPUT_NDISCRETES_Number))
    {
        iRegIndex = (unsigned short) (usAddress - S_DISCRETE_INPUT_START_Pos) / 8;
        iRegBitIndex = (unsigned short) (usAddress - S_DISCRETE_INPUT_START_Pos) % 8;

        while (iNReg > 0)
        {
            *pucRegBuffer++ = WHT_MB_Util_Get_Bits(&WHT_SDiscIn_Buffer[iRegIndex++], iRegBitIndex, 8);
            iNReg--;
        }
        pucRegBuffer--;
        /* 最后的离散量 */
        usNDiscrete = usNDiscrete % 8;
        /* 向高位补零 */
        *pucRegBuffer = *pucRegBuffer << (8 - usNDiscrete);
        *pucRegBuffer = *pucRegBuffer >> (8 - usNDiscrete);
    }
    else
    {
        eStatus = MB_ENOREG;
    }

    return eStatus;
}


__weak void WHT_FreeModBus_Lite_Init(eMBMode eMode,  uint8_t Slave_Address)
{
	/* ModBus初始化 */
    WHT_MB_Init(eMode, Slave_Address);
}
__weak void WHT_FreeModBus_Lite_Poll(void)
{
    /* ModBus无限轮询*/
    WHT_MB_Poll();
}
